﻿using System;

namespace _01单例模式.懒汉式
{
    public class SingleLayMan
    {
        //1、私有化构造函数
        private SingleLayMan()
        {

        }
        //2、声明静态字段  存储我们唯一的对象实例
        private static SingleLayMan _singleLayMan;
        //通过方法 创建实例并返回
        public static SingleLayMan GetSingleLayMan1()
        {
            //这种方式不可用  会创建多个对象，谨记
            return _singleLayMan = new SingleLayMan();
        }
        /// <summary>
        ///懒汉式单例模式只有在调用方法时才会去创建，不会造成资源的浪费
        /// </summary>
        /// <returns></returns>
        public static SingleLayMan GetSingleLayMan2()
        {
            if (_singleLayMan == null)
            {
                Console.WriteLine("我被创建了一次！");
                _singleLayMan = new SingleLayMan();
            }
            return _singleLayMan;
        }
        private static object _oj = new object();
        /// <summary>
        /// 该方式也可解决线程问题，但请求进来，每次都要lock排队等待，消耗资源
        /// </summary>
        public static SingleLayMan GetSingleLayMan3()
        {
            lock (_oj)
            {
                if (_singleLayMan == null)
                {
                    _singleLayMan = new SingleLayMan();
                    //Console.WriteLine("我被创建了一次！");
                }
            }            
            return _singleLayMan;
        }

        /// <summary>
        /// 解决多线程安全问题，双重锁定，减少系统消耗，节约资源
        /// </summary>
        public static SingleLayMan GetSingleLayMan4()
        {
            if (_singleLayMan == null)
            {
                lock (_oj)
                {
                    if (_singleLayMan == null)
                    {
                        _singleLayMan = new SingleLayMan();
                        Console.WriteLine("我被创建了一次！");
                    }
                }
            }           
            return _singleLayMan;
        }
    }

    public class SingleLayManTest
    {
        /// <summary>
        /// 会创建多个对象.hash值不一样
        /// </summary>
        public static void FactTest()
        {
            Console.WriteLine("单例模式.懒汉式测试!");
            var singleLayMan1 = SingleLayMan.GetSingleLayMan1();
            var singleLayMan2 = SingleLayMan.GetSingleLayMan1();
            Console.WriteLine(singleLayMan1.GetHashCode());
            Console.WriteLine(singleLayMan2.GetHashCode());
        }
        /// <summary>
        /// 单例模式.懒汉式测试：懒汉式单例模式只有在调用方法时才会去创建，不会造成资源的浪费,但会有线程安全问题
        /// </summary>
        public static void FactTest1()
        {
            Console.WriteLine("单例模式.懒汉式测试!");
            var singleLayMan1 = SingleLayMan.GetSingleLayMan2();
            var singleLayMan2 = SingleLayMan.GetSingleLayMan2();
            Console.WriteLine(singleLayMan1.GetHashCode());
            Console.WriteLine(singleLayMan2.GetHashCode());
        }
        /// <summary>
        /// 单例模式.懒汉式多线程环境测试!
        /// </summary>
        public static void FactTest2()
        {
            Console.WriteLine("单例模式.懒汉式多线程环境测试!");
            for (int i = 0; i < 10; i++)
            {
                new Thread(() =>
                {
                    SingleLayMan.GetSingleLayMan2();
                }).Start();
            }

            //Parallel.For(0, 10, d => {
            //    SingleLayMan.GetSingleLayMan2();
            //});
        }
    }
}
